//  This file is part of NHibernate.ReLinq.Sample a sample showing
//  the use of the open source re-linq library to implement a non-trivial 
//  Linq-provider, on the example of NHibernate (www.nhibernate.org).
//  Copyright (C) 2005-2009 rubicon informationstechnologie gmbh, www.rubicon.eu
//  
//  NHibernate.ReLinq.Sample is based on re-motion re-linq (http://www.re-motion.org/).
//  
//  NHibernate.ReLinq.Sample is free software; you can redistribute it 
//  and/or modify it under the terms of the MIT License 
// (http://www.opensource.org/licenses/mit-license.php).
// 
using System;
using System.Collections.Generic;
using System.Text;
using Remotion.Linq.Clauses;

namespace NHibernate.ReLinq.Sample.HqlQueryGeneration
{
    public class QueryPartsAggregator
    {
        private string _selectPart;

        // 包含 FromParts WhereParts OrderByParts 三部分 Hql 集合和一个 SelectPart 
        public QueryPartsAggregator()
        {
            FromParts = new List<string>();
            WhereParts = new List<string>();
            OrderByParts = new List<string>();
        }

        public string SelectPart
        {
            get
            {
                return _selectPart;
            }
            set
            {
                Console.WriteLine($"*SelectPart -> [select] {value}*");
                _selectPart = value;
            }

        }
        private List<string> FromParts { get; set; }
        private List<string> WhereParts { get; set; }
        private List<string> OrderByParts { get; set; }

        public void AddFromPart(IQuerySource querySource)
        {
            // from pn in NHQueryFactory.Queryable<PhoneNumber>(session)
            // 例如 {NHibernate.ReLinq.Sample.UnitTests.DomainObjects.PhoneNumber} as {pn}
            var tp = string.Format("{0} as {1}", GetEntityName(querySource), querySource.ItemName);
            Console.WriteLine($"*AddFromPart -> [from] {tp}*");
            FromParts.Add(tp);
        }

        public void AddWherePart(string formatString, params object[] args)
        {
            var tp = string.Format(formatString, args);
            Console.WriteLine($"*AddWherePart -> [where] {tp}*");
            WhereParts.Add(tp);
        }

        public void AddOrderByPart(IEnumerable<string> orderings)
        {
            var tp = String.Join(", ", orderings);
            Console.WriteLine($"*AddOrderByPart -> [order by] {tp}*");
            OrderByParts.Insert(0, tp);
        }

        public string BuildHQLString()
        {
            var stringBuilder = new StringBuilder();

            if (string.IsNullOrEmpty(SelectPart) || FromParts.Count == 0)
                throw new InvalidOperationException("A query must have a select part and at least one from part.");

            stringBuilder.AppendFormat("select {0}", SelectPart);
            stringBuilder.AppendFormat(" from {0}", String.Join(", ", FromParts));

            if (WhereParts.Count > 0)
                stringBuilder.AppendFormat(" where {0}", String.Join(" and ", WhereParts));

            if (OrderByParts.Count > 0)
                stringBuilder.AppendFormat(" order by {0}", String.Join(", ", OrderByParts));

            Console.WriteLine($"#BuildHQLString -> {stringBuilder.ToString()}#");

            return stringBuilder.ToString();
        }

        private string GetEntityName(IQuerySource querySource)
        {
            // 得到 NHibernate 实体的全名称
            return NHibernateUtil.Entity(querySource.ItemType).Name;
        }
    }
}